﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Monads;
using System.Runtime.CompilerServices;

using ABCat.Core;
using ABCat.Core.Editors;
using ABCat.Core.Plugins;
using ABCat.Shared;
using ABCat.Shared.Properties;

namespace ABCat.Plugins.Parsers.Rutracker
{
	[UsedImplicitly]
	[DisplayName("Загрузка торрент-файлов")]
	public sealed class RutrackerTorrentFilesDownloaderConfig : Config
	{
		#region + Fields +

		private string _audioCatalogFolder;
		private string _torrentClientName;
		private TorrentFileActionEnum _torrentFileAction;
		private string _torrentFilesFolder;

		#endregion
		#region + Properties +

		public override string DisplayName
		{
			get { return "Загрузка торрент-файлов"; }
		}

		[DisplayName("Каталог контента")]
		[Description("Путь к папке, в которой будет храниться загружаемый контент. ABCat может создавать иерархию внутри этой папки согласно логике группировки контента. У ABCat должны быть права на запись в указанную папку.")]
		[Editor(typeof(FolderPathEditor), typeof(FolderPathEditor))]
		public string AudioCatalogFolder
		{
			get { return _audioCatalogFolder; }
			set
			{
				if (value == _audioCatalogFolder) return;
				_audioCatalogFolder = value;
				OnPropertyChanged();
			}
		}

		[DisplayName("Torrent-клиент")]
		[Description("Найденные установки Torrent-клиентов, поддерживаемые ABCat")]
		[Editor(typeof(ComboBoxEditor), typeof(ComboBoxEditor))]
		public string TorrentClientName
		{
			get { return _torrentClientName; }
			set
			{
				if (value == _torrentClientName) return;
				_torrentClientName = value;
				OnPropertyChanged();
			}
		}

		[DisplayName("Действие")]
		[Description("Что нужно делать с загруженными torrent-файлами")]
		[Editor(typeof(EnumEditor), typeof(EnumEditor))]
		public TorrentFileActionEnum TorrentFileAction
		{
			get { return _torrentFileAction; }
			set
			{
				if (value == _torrentFileAction) return;
				_torrentFileAction = value;
				OnPropertyChanged();
			}
		}

		[DisplayName("Хранилище torrent-файлов")]
		[Description("Папка для сохранения загруженных *.torrent файлов")]
		[Editor(typeof(FolderPathEditor), typeof(FolderPathEditor))]
		public string TorrentFilesFolder
		{
			get { return _torrentFilesFolder; }
			set
			{
				if (value == _torrentFilesFolder) return;
				_torrentFilesFolder = value;
				OnPropertyChanged();
			}
		}

		[DisplayName("Сохранять куки")]
		[Description("Сохранять куки для повторной авторизации на rutracker")]
		public bool SaveCoockies
		{
			get { return _saveCoockies; }
			set
			{
				if (value.Equals(_saveCoockies)) return;
				_saveCoockies = value;
				OnPropertyChanged("SaveCoockies");
			}
		}

		[Browsable(false)]
		public string CoockieFileName { get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "ABCat", "Coockies", "rutracker"); } }

		#endregion
		#region + Ctor +

		public RutrackerTorrentFilesDownloaderConfig()
		{
			var knownClients = new HashSet<string>();
			knownClients.Add("BitTorrent");
			knownClients.Add("µTorrent");
			_torrentClients = Extensions.GetInstalledApplications().Where(item => knownClients.Contains(item.DisplayName)).ToArray();
			ComboBoxEditor.Register("TorrentClientName", new ObservableCollection<object>(_torrentClients.Select(GetTorrentClientName)));
			SaveCoockies = true;
		}

		private readonly IEnumerable<Extensions.InstalledApplication> _torrentClients;
		private bool _saveCoockies;
		private string _coockiesFolder;

		private string GetTorrentClientName(Extensions.InstalledApplication installedApplication)
		{
			return "{0} [{1}]".F(installedApplication.DisplayName, installedApplication.DisplayVersion);
		}

		#endregion
		#region + Logic +

		public override bool Check(bool correct)
		{
			bool result = true;

			if (AudioCatalogFolder.IsNullOrEmpty()) AudioCatalogFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "ABCat", "AudioCatalog");
			if (TorrentFilesFolder.IsNullOrEmpty()) TorrentFilesFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "ABCat", "TorrentFiles");

			if (TorrentClientName.IsNullOrEmpty())
			{
				if (_torrentClients.AnySafe())
				{
					var firstClient = _torrentClients.First();
					TorrentClientName = GetTorrentClientName(firstClient);
				}
			}

			string coockiesDirectoryName = Path.GetDirectoryName(CoockieFileName);
			if (coockiesDirectoryName.IsNullOrEmpty()) throw new ABCatException("Неожиданно не удалось вычислить заданный хардкодом путь к папке куков. Привет JetBrains и их проверке на PossibleNullReferenceException.", ExceptionTypeEnum.Stop, null, true);

			if (!Directory.Exists(coockiesDirectoryName)) Directory.CreateDirectory(coockiesDirectoryName);

			if (!Directory.Exists(AudioCatalogFolder))
			{
				result = false;
				if (correct) Directory.CreateDirectory(AudioCatalogFolder);
			}
			if (!Directory.Exists(TorrentFilesFolder))
			{
				result = false;
				if (correct) Directory.CreateDirectory(TorrentFilesFolder);
			}

			result = result && CheckDirectory(AudioCatalogFolder) && CheckDirectory(TorrentFilesFolder);

			if (TorrentFileAction == TorrentFileActionEnum.StartDownload)
			{
				if (TorrentClientName.IsNullOrEmpty()) result = false;
				else
				{
					var torrentClient = GetTorrentClient();
					if (torrentClient == null || !File.Exists(torrentClient.ExePath))
					{
						result = false;
					}
				}
			}

			return result;
		}

		[CanBeNull]
		public Extensions.InstalledApplication GetTorrentClient()
		{
			var ia = Extensions.GetInstalledApplications().FirstOrDefault(item => "{0} [{1}]".F(item.DisplayName, item.DisplayVersion) == TorrentClientName);
			if (ia != null)
			{
				switch (ia.DisplayName.ToLower())
				{
					case "bittorrent":
						ia.ExePath = Path.Combine(ia.InstallLocation, "bittorrent.exe");
						break;
					case "µtorrent":
						ia.ExePath = Path.Combine(ia.InstallLocation, "utorrent.exe");
						break;
				}
			}
			return ia;
		}

		#endregion
		#region # Enums #

		public enum TorrentFileActionEnum
		{
			[Description("Запустить загрузку в торрент-клиенте")]
			StartDownload,
			[Description("Показать в проводнике")]
			None,
			[Description("Выполнить системное действие")]
			SystemAction,
		}

		#endregion
	}
}